#include "SemanticNodeMethodBody.h"

#include "SemanticNodeMethodStatement.h"
#include "../errors_warnings.h"
class SemanticNodeVariableDefinition;


SemanticNodeMethodBody::SemanticNodeMethodBody (SyntaxTreeNode *syntaxNode, SemanticNode *parent) : SemanticNode(parent) {

	if (syntaxNode->Production == Gr_MethodBodyDecl__spSemiCol || syntaxNode->Production == Gr_ConstrBody__spSemiCol)
		return;

	if (syntaxNode->Production == Gr_MethodBodyDecl__spLCBrac_MethodBody_spRCBrac || syntaxNode->Production == Gr_ConstrBody__spLCBrac_MethodBody_spRCBrac)
		syntaxNode = syntaxNode->Nodes->GetData(1);

	for (int i = 0; i < syntaxNode->Nodes->GetCount(); ++i) {
		SyntaxTreeNode *tempLabels = syntaxNode->Nodes->GetData(i)->Nodes->GetData(0);
		SyntaxTreeNode *statement = syntaxNode->Nodes->GetData(i)->Nodes->GetData(1);

		SemanticNode *semanticStatement = NULL;
		switch (statement->Production) {
		case Gr_MethodStatement__VariableDefinition:
			{
				std::vector<SemanticNodeVariableDefinition*> tempVars = SemanticNodeVariableDefinition::analyzeNodeVariableDefinition(statement->Nodes->GetData(0), this);
				for (std::vector<SemanticNodeVariableDefinition*>::iterator i = tempVars.begin(); i != tempVars.end(); ++i) {
					if (semanticStatement == NULL)
						semanticStatement = *i;
					statements.push_back(*i);
					addVariable(*i);
				}
			}
			break;
		case Gr_MethodStatement__Assignment:
			statements.push_back(semanticStatement = new SemanticNodeAssignment(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__MethodCall:
			statements.push_back(semanticStatement = new SemanticNodeMethodCall(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__IfStatement:
			statements.push_back(semanticStatement = new SemanticNodeIfStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__WhileStatement:
			statements.push_back(semanticStatement = new SemanticNodeWhileStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__ForStatement:
			statements.push_back(semanticStatement = new SemanticNodeForStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__DowhileStatement:
			statements.push_back(semanticStatement = new SemanticNodeWhileStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__SwitchCaseStatement:
			statements.push_back(semanticStatement = new SemanticNodeSwitchCaseStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__BreakStatement:
			statements.push_back(semanticStatement = new SemanticNodeBreakStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__ContinueStatement:
			statements.push_back(semanticStatement = new SemanticNodeContinueStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__ReturnStatement:
			statements.push_back(semanticStatement = new SemanticNodeReturnStatement(statement->Nodes->GetData(0),this));
			break;
		case Gr_MethodStatement__GotoStatement:
			statements.push_back(semanticStatement = new SemanticNodeGotoStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__StartStatement:
			statements.push_back(semanticStatement = new SemanticNodeStartStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__StopStatement:
			statements.push_back(semanticStatement = new SemanticNodeStopStatement(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__AssignmentDerivation:
			statements.push_back(semanticStatement = new SemanticNodeAssignment(statement->Nodes->GetData(0), this));
			break;
		case Gr_MethodStatement__BlockStatement:
			statements.push_back(semanticStatement = new SemanticNodeMethodBody(statement->Nodes->GetData(0)->Nodes->GetData(1), this));
			break;
		case Gr_MethodStatement__epsilon:
			break;
		default:
			//TODO ne bi trebalo biti moguce
			break;
		}

		for (int j = 0; j < tempLabels->Nodes->GetCount(); ++j) {
			LexicUnit lu = CompilerData->Units->GetLexicUnit(tempLabels->Nodes->GetData(j)->Nodes->GetData(0)->LexUnitID);
			std::string label = CompilerData->Units->GetLexicUnitString(&lu);
			if (labels.find(label) == labels.end()){
				labels[label] = semanticStatement;
			} else {
				CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_LABEL_ALREADY_EXISTS);
			}
		}

	}




}


void SemanticNodeMethodBody::addVariable (SemanticNodeVariableDefinition *var) {
	//TODO provjeri da li vec postoji istoimena varijabla, treba provjeriti u ovom method bodyju i u method bodyjima koji su iznad u hijerarhiji

	variables.push_back(var);
}






std::string SemanticNodeMethodBody::toDebugString (int tab) {
	std::ostringstream ss;
	for (int i = 0; i < tab; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "methodBody {" << std::endl;

	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "Labele: { ";
	for (std::map<std::string, SemanticNode*>::iterator i = labels.begin(); i != labels.end(); ++i)
		ss << i->first << " ";
	ss << "}" << std::endl;

	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "Varijable: {" << std::endl;
	for (std::vector<SemanticNodeVariableDefinition*>::iterator i = variables.begin(); i != variables.end(); ++i)
		ss << (*i)->toDebugString(tab + 2);
	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "}" << std::endl;

	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
		ss << "Redoslijed naredbi: {" << std::endl;
	for (std::vector<SemanticNode*>::iterator i = statements.begin(); i != statements.end(); ++i)
		ss << (*i)->toDebugString(tab + 2);
	for (int i = 0; i < tab + 1; i++) ss << DEBUG_STRING_RAZMAK;
	ss << "}" << std::endl;

	for (int i = 0; i < tab; i++) ss << DEBUG_STRING_RAZMAK;
		ss << "}" << std::endl;
	return ss.str();
}

